@file:Suppress("MemberVisibilityCanBePrivate")

package com.virtualightning.mvvm.impl.task

import kotlinx.coroutines.*
import java.io.Closeable
import java.lang.Runnable

/**
 *  Anchor : Create by CimZzz
 *  Time : 2021/10/11 16:09
 *  Task 基类
 */
abstract class BaseTask<T>(private val deferred: ProgressDeferred<T?> = progressDeferred()): ProgressDeferred<T?> by deferred, Runnable, Closeable {
	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:44 PM
	// 判断当前 Task 是否已经启动
	///////////////////////////////////////////////////////////////////////////
	protected var isStarted = false

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:19 PM
	// 判断当前 Task 是否被取消
	///////////////////////////////////////////////////////////////////////////
	protected var isCanceled = false

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:39 PM
	// Closeable Set
	///////////////////////////////////////////////////////////////////////////
	private val closeableSet: HashSet<Closeable> by lazy { HashSet() }

	override fun run() {
		val result = kotlin.runCatching {
			if(!isCanceled) {
				doTask()
			}
			else {
				null
			}
		}
		synchronized(this) {
			if(isCanceled) {
				onRelease()
				return
			}
			isCanceled = true
		}
		if(result.isSuccess) {
			deferred.complete(result.getOrNull())
		}
		else {
			onRelease()
			deferred.completeExceptionally(result.exceptionOrNull() ?: RuntimeException("Unknown error"))
		}
	}

	override fun close() {
		cancel(null)
	}


	override fun start(): Boolean {
		if(isStarted || isCanceled) {
			return false
		}
		isStarted = true
		startTask()
		return true
	}

	override fun cancel(cause: CancellationException?) {
		synchronized(this) {
			if(isCanceled) {
				return
			}
			isCanceled = true
		}
		deferred.cancel(cause)
		closeableSet.forEach {
			closeable ->
			kotlin.runCatching {
				closeable.close()
			}
		}
		onClosed()
	}

	///////////////////////////////////////////////////////////////////////////
	// 代码分割线 on 2021/10/11 4:40 PM by CimZzz
	// 以下内容为:
	// 内部方法
	///////////////////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:40 PM
	// 添加 Closeable，在 Task 被主动关闭时一并回收
	///////////////////////////////////////////////////////////////////////////
	protected fun attachCloseable(closeable: Closeable) {
		synchronized(this) {
			if(isCanceled) {
				kotlin.runCatching { closeable.close() }
				return
			}
		}

		closeableSet.add(closeable)
	}


	/**
	 * 任务执行异常/中断会触发回调，用于释放资源
	 */
	protected open fun onRelease() {

	}

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:41 PM
	// 关闭回调
	///////////////////////////////////////////////////////////////////////////
	protected open fun onClosed() {

	}

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:42 PM
	// 启动 Task
	///////////////////////////////////////////////////////////////////////////
	protected abstract fun startTask()

	///////////////////////////////////////////////////////////////////////////
	// Add by CimZzz on 2021/10/11 4:20 PM
	// 执行 Task 任务
	///////////////////////////////////////////////////////////////////////////
	protected abstract fun doTask(): T

	/**
	 * 抛出中断异常
	 */
	protected fun throwCancelException() {
		throw RuntimeException("Task is canceled")
	}
}